﻿using OpenQA.Selenium;
using OpenQA.Selenium.Support.UI;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Linq;

public static class SeleniumHelperExt
{
    #region 封装WebDriver的操作
    /// <summary>
    /// 等待,ExpectedConditions,SeleniumExtras.WaitHelpers.ExpectedConditions
    /// </summary>
    public static TResult ExtUntil<TResult>(this IWebDriver webDriver, Func<IWebDriver, TResult> condition, TimeSpan? timeout = null)
    {
        timeout = timeout ?? TimeSpan.FromSeconds(10);
        WebDriverWait wait = new WebDriverWait(webDriver, timeout.Value);
        return wait.Until(condition);
    }
    /// <summary>
    /// 元素点击
    /// </summary>
    public static IWebElement ExtClick(this IWebDriver webDriver, By by)
    {
        IWebElement element = webDriver.FindElement(by);
        element.Click();
        return element;
    }

    /// <summary>
    /// 获取元素的innerHTML
    /// </summary>
    public static string ExtGetInnerHTML(this IWebDriver @this, By by)
    {
        return @this.FindElement(by)?.GetAttribute("innerHTML");
    }

    /// <summary>
    /// 获取元素的innerText
    /// </summary>
    public static string ExtGetInnerText(this IWebDriver @this, By by)
    {
        return @this.FindElement(by)?.Text;
    }

    /// <summary>
    /// 获取元素的outerHTML
    /// </summary>
    public static string ExtGetOuterHTML(this IWebDriver @this, By by)
    {
        return @this.FindElement(by)?.GetAttribute("outerHTML");
    }

    public static IWebElement ExtFindElement(this IWebDriver @this, By by)
    {
        try
        {
            return @this.FindElement(by);
        }
        catch (NoSuchElementException)
        {
            return null;
        }
    }

    public static void ExtScroll(this IWebDriver @this, int yOffset)
    {
        @this.ExtExecuteScript($"window.scrollBy(0,{yOffset});");
    }
    public static ReadOnlyCollection<IWebElement> ExtFindElements(this IWebDriver @this, By by)
    {
        try
        {
            return @this.FindElements(by);
        }
        catch (NoSuchElementException)
        {
        }
        return null;
    }

    /// <summary>
    /// 显示元素，true-使元素显示在页码最上方
    /// </summary>
    public static IWebElement ExtScrollIntoView(this IWebDriver webDriver, By by, bool scrollFlag = true)
    {
        IWebElement element = webDriver.FindElement(by);
        ExtExecuteScript(webDriver, $"arguments[0].scrollIntoView({scrollFlag.ToString().ToLower()});", element);
        return element;
    }

    /// <summary>
    /// 元素点击
    /// </summary>
    public static IWebElement ExClickByJs(this IWebDriver webDriver, By by)
    {
        IWebElement el = null;
        try
        {
            el = webDriver.FindElement(by);
            ExtExecuteScript(webDriver, "arguments[0].click();", el);
            //ExExecuteScript(webDriver, "arguments[0].scrollIntoView(true);", el);
            //ExUntil(webDriver, ExpectedConditions.ElementToBeClickable(by));
            //el.Click();
            return el;
        }
        catch (WebDriverTimeoutException)
        {
            return el;
        }
        catch (Exception)
        {
            throw;
        }
    }

    public static IWebElement ExtSubmit(this IWebDriver webDriver, By by)
    {
        IWebElement element = webDriver.FindElement(by);
        element.Submit();
        return element;
    }

    public static IWebElement ExtSendKeys(this IWebDriver webDriver, By by, string text, bool useClean = false)
    {
        IWebElement el = webDriver.FindElement(by);
        if (useClean)
            el.Clear();
        el.SendKeys(text);
        return el;
    }

    public static IWebElement ExtSelectByValue(this IWebDriver webDriver, By by, string value)
    {
        var element = webDriver.FindElement(by);
        SelectElement select = new SelectElement(element);
        select.SelectByValue(value);
        return element;
    }

    public static bool ExIsFirefoxPageError(this IWebDriver webDriver)
    {
        //建立安全连接失败 or 页面载入出错
        return Regex.IsMatch(webDriver.PageSource, "&loadError.label;</title>")
            || Regex.IsMatch(webDriver.PageSource, "页面载入出错");
    }

    public static bool IsComplete(this IWebDriver webDriver)
    {
        string result = webDriver.ExtExecuteScript("return document.readyState") as string;
        return result == "complete";
    }

    public static async Task WaitToComplete(this IWebDriver webDriver)
    {
        //await Task.Delay(1000);
        while (!webDriver.IsComplete())
        {
            await Task.Delay(100);
        }
    }

    /// <summary>
    /// 截图
    /// </summary>
    /// <param name="filename"></param>
    public static void ExtScreenshot(this IWebDriver webDriver, string filePath)
    {
        ITakesScreenshot drivername = (ITakesScreenshot)webDriver;
        Screenshot scrFile = drivername.GetScreenshot();
        try
        {
            scrFile.SaveAsFile(filePath, ScreenshotImageFormat.Png);
            Console.WriteLine($@"{filePath} screen shot finished");
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
        }
        finally
        {
        }
    }


    /// <summary>
    /// 页面跳转
    /// </summary>
    /// <param name="url"></param>
    public static void ExtGoToUrl(this IWebDriver webDriver, string url)
    {
        try
        {
            webDriver.Url = url;
        }
        catch (WebDriverTimeoutException)
        {
        }
        catch (Exception)
        {
            throw;
        }
    }

    /// <summary>
    /// 在新标签打开网页
    /// </summary>
    /// <param name="webDriver"></param>
    /// <param name="url"></param>
    /// <param name="action"></param>
    /// <returns></returns>
    public static Task ExtGotoNewTab(this IWebDriver webDriver, string url, Action action)
    {
        return ExtGotoNewTab(webDriver, url, () => Task.Run(() => action));
    }

    /// <summary>
    /// 在新标签打开网页
    /// </summary>
    /// <param name="webDriver"></param>
    /// <param name="url"></param>
    /// <param name="func"></param>
    /// <returns></returns>
    public static async Task ExtGotoNewTab(this IWebDriver webDriver, string url, Func<Task> func)
    {
        try
        {
            if (string.IsNullOrEmpty(url))
                throw new ArgumentNullException(nameof(url));
            var currentWindow = webDriver.CurrentWindowHandle;
            webDriver.ExtExecuteScript($"window.open('{url}')");
            await Task.Delay(1000);
            if (webDriver.WindowHandles.Count > 1)
            {
                webDriver.SwitchTo().Window(webDriver.WindowHandles.Last());
                await func();
                webDriver.Close();
                webDriver.SwitchTo().Window(currentWindow);
            }
        }
        catch (WebDriverTimeoutException)
        {
        }
        catch (Exception)
        {
            throw;
        }
    }

    public static async Task ExtWaitToUrl(this IWebDriver webDriver, params string[] urls)
    {
        int i = 20;
        while (i-- > 0)
        {
            if (webDriver.ExIsFirefoxPageError())
                throw new Exception("IsFirefoxPageError");
            foreach (var url in urls)
            {
                if (webDriver.Url.Contains(url))
                {
                    await webDriver.WaitToComplete();
                    return;
                }
            }
            await Task.Delay(500);
        }
        if (i <= 0)
            throw new Exception("timeout");
    }

    public static async Task ExWaitToUrl(this IWebDriver webDriver, int seconds, params string[] urls)
    {
        int i = seconds;
        while (i-- > 0)
        {
            if (webDriver.ExIsFirefoxPageError())
                throw new Exception("IsFirefoxPageError");
            foreach (var url in urls)
            {
                if (webDriver.Url.Contains(url))
                {
                    await webDriver.WaitToComplete();
                    return;
                }
            }
            await Task.Delay(1000);
        }
        if (i <= 0)
            throw new Exception("timeout");
    }


    public static object ExtExecuteScript(this IWebDriver webDriver, string script, params object[] args)
    {
        try
        {
            IJavaScriptExecutor js = ((IJavaScriptExecutor)webDriver);
            return js.ExecuteScript(script, args);
        }
        catch (WebDriverTimeoutException)
        {
        }
        catch (Exception)
        {
            throw;
        }
        return null;
    }


    public static CookieContainer ExtGetCookieContainer(this IWebDriver webDriver)
    {
        CookieContainer cc = new CookieContainer();
        var allCookies = webDriver.Manage().Cookies.AllCookies;
        foreach (var cookie in allCookies)
        {
            try
            {
                System.Net.Cookie c = new System.Net.Cookie(cookie.Name, cookie.Value.Replace(",", "%2C"), cookie.Path, cookie.Domain)
                {
                    Expires = DateTime.Now.AddYears(1)
                };
                cc.Add(c);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }
        return cc;
    }

    public static List<System.Net.Cookie> ExtGetCookiesList(this IWebDriver webDriver)
    {
        var result = new List<System.Net.Cookie>();
        var allCookies = webDriver.Manage().Cookies.AllCookies;
        foreach (var cookie in allCookies)
        {
            try
            {
                System.Net.Cookie c = new System.Net.Cookie(cookie.Name, cookie.Value, cookie.Path, cookie.Domain)
                {
                    //System.Net.Cookie c = new System.Net.Cookie(cookie.Name, cookie.Value.Replace(",", "%2C"), cookie.Path, cookie.Domain);
                    Expires = DateTime.Now.AddYears(1)
                };
                result.Add(c);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }
        return result;
    }

    public static string ExtGetCookiesString(this IWebDriver webDriver)
    {
        var result = new StringBuilder();
        return string.Concat(webDriver.Manage().Cookies.AllCookies
            .Select(it => $"{it.Name}={it.Value.Replace(",", "%2C")};"));
    }

    public static IWebDriver ExSetCookies(this IWebDriver webDriver, List<System.Net.Cookie> cookies, string domain)
    {
        if (cookies == null)
            throw new ArgumentNullException();
        foreach (var item in cookies)
        {
            try
            {
                webDriver.Manage().Cookies.DeleteCookieNamed(item.Name);
                webDriver.Manage().Cookies.AddCookie(new OpenQA.Selenium.Cookie(item.Name, item.Value, item.Domain, item.Path, DateTime.Now.AddYears(1)));
            }
            catch (Exception)
            {
                //Console.WriteLine(ex.Message);
            }
            //webDriver.Manage().Cookies.AddCookie(new OpenQA.Selenium.Cookie(item.Name, item.Value, domain, item.Path, DateTime.Now.AddYears(1)));
        }
        return webDriver;
    }

    public static string ExGetCookiesString(this IWebDriver webDriver)
    {
        string cc = string.Empty;
        var allCookies = webDriver.Manage().Cookies.AllCookies;
        foreach (var cookie in allCookies)
        {
            try
            {
                cc = cc + $"{cookie.Name}={cookie.Value.Replace(",", "%2C")};";
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }
        return cc;
    }

    /// <summary>
    /// 验证登陆
    /// </summary>
    /// <param name="webDriver"></param>
    /// <param name="user"></param>
    /// <param name="psw"></param>
    public static void ExLogin(this IWebDriver webDriver, string user, string psw)
    {
        IAlert alert = webDriver.SwitchTo().Alert();
        alert.SendKeys(user + Keys.Tab + psw);
        alert.Accept();
    }


    #endregion
}
